1   /*
2    * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package javax.swing.plaf.basic;
27  
28  import javax.swing.*;
29  import javax.swing.event.*;
30  import java.awt.*;
31  import java.awt.event.*;
32  
33  import java.beans.*;
34  
35  import java.util.Hashtable;
36  import java.util.HashMap;
37  
38  import javax.swing.border.*;
39  import javax.swing.plaf.*;
40  import sun.swing.DefaultLookup;
41  import sun.swing.UIAction;
42  
43  
44  /**
45   * A Basic L&F implementation of ToolBarUI.  This implementation
46   * is a "combined" view/controller.
47   * <p>
48   *
49   * @author Georges Saab
50   * @author Jeff Shapiro
51   */
52  public class BasicToolBarUI extends ToolBarUI implements SwingConstants
53  {
54      protected JToolBar toolBar;
55      private boolean floating;
56      private int floatingX;
57      private int floatingY;
58      private JFrame floatingFrame;
59      private RootPaneContainer floatingToolBar;
60      protected DragWindow dragWindow;
61      private Container dockingSource;
62      private int dockingSensitivity = 0;
63      protected int focusedCompIndex = -1;
64  
65      protected Color dockingColor = null;
66      protected Color floatingColor = null;
67      protected Color dockingBorderColor = null;
68      protected Color floatingBorderColor = null;
69  
70      protected MouseInputListener dockingListener;
71      protected PropertyChangeListener propertyListener;
72  
73      protected ContainerListener toolBarContListener;
74      protected FocusListener toolBarFocusListener;
75      private Handler handler;
76  
77      protected String constraintBeforeFloating = BorderLayout.NORTH;
78  
79      // Rollover button implementation.
80      private static String IS_ROLLOVER = "JToolBar.isRollover";
81      private static Border rolloverBorder;
82      private static Border nonRolloverBorder;
83      private static Border nonRolloverToggleBorder;
84      private boolean rolloverBorders = false;
85  
86      private HashMap<AbstractButton, Border> borderTable = new HashMap<AbstractButton, Border>();
87      private Hashtable<AbstractButton, Boolean> rolloverTable = new Hashtable<AbstractButton, Boolean>();
88  
89  
90      /**
91       * As of Java 2 platform v1.3 this previously undocumented field is no
92       * longer used.
93       * Key bindings are now defined by the LookAndFeel, please refer to
94       * the key bindings specification for further details.
95       *
96       * @deprecated As of Java 2 platform v1.3.
97       */
98      @Deprecated
99      protected KeyStroke upKey;
100     /**
101      * As of Java 2 platform v1.3 this previously undocumented field is no
102      * longer used.
103      * Key bindings are now defined by the LookAndFeel, please refer to
104      * the key bindings specification for further details.
105      *
106      * @deprecated As of Java 2 platform v1.3.
107      */
108     @Deprecated
109     protected KeyStroke downKey;
110     /**
111      * As of Java 2 platform v1.3 this previously undocumented field is no
112      * longer used.
113      * Key bindings are now defined by the LookAndFeel, please refer to
114      * the key bindings specification for further details.
115      *
116      * @deprecated As of Java 2 platform v1.3.
117      */
118     @Deprecated
119     protected KeyStroke leftKey;
120     /**
121      * As of Java 2 platform v1.3 this previously undocumented field is no
122      * longer used.
123      * Key bindings are now defined by the LookAndFeel, please refer to
124      * the key bindings specification for further details.
125      *
126      * @deprecated As of Java 2 platform v1.3.
127      */
128     @Deprecated
129     protected KeyStroke rightKey;
130 
131 
132     private static String FOCUSED_COMP_INDEX = "JToolBar.focusedCompIndex";
133 
134     public static ComponentUI createUI( JComponent c )
135     {
136         return new BasicToolBarUI();
137     }
138 
139     public void installUI( JComponent c )
140     {
141         toolBar = (JToolBar) c;
142 
143         // Set defaults
144         installDefaults();
145         installComponents();
146         installListeners();
147         installKeyboardActions();
148 
149         // Initialize instance vars
150         dockingSensitivity = 0;
151         floating = false;
152         floatingX = floatingY = 0;
153         floatingToolBar = null;
154 
155         setOrientation( toolBar.getOrientation() );
156         LookAndFeel.installProperty(c, "opaque", Boolean.TRUE);
157 
158         if ( c.getClientProperty( FOCUSED_COMP_INDEX ) != null )
159         {
160             focusedCompIndex = ( (Integer) ( c.getClientProperty( FOCUSED_COMP_INDEX ) ) ).intValue();
161         }
162     }
163 
164     public void uninstallUI( JComponent c )
165     {
166 
167         // Clear defaults
168         uninstallDefaults();
169         uninstallComponents();
170         uninstallListeners();
171         uninstallKeyboardActions();
172 
173         // Clear instance vars
174         if (isFloating())
175             setFloating(false, null);
176 
177         floatingToolBar = null;
178         dragWindow = null;
179         dockingSource = null;
180 
181         c.putClientProperty( FOCUSED_COMP_INDEX, Integer.valueOf( focusedCompIndex ) );
182     }
183 
184     protected void installDefaults( )
185     {
186         LookAndFeel.installBorder(toolBar,"ToolBar.border");
187         LookAndFeel.installColorsAndFont(toolBar,
188                                               "ToolBar.background",
189                                               "ToolBar.foreground",
190                                               "ToolBar.font");
191         // Toolbar specific defaults
192         if ( dockingColor == null || dockingColor instanceof UIResource )
193             dockingColor = UIManager.getColor("ToolBar.dockingBackground");
194         if ( floatingColor == null || floatingColor instanceof UIResource )
195             floatingColor = UIManager.getColor("ToolBar.floatingBackground");
196         if ( dockingBorderColor == null ||
197              dockingBorderColor instanceof UIResource )
198             dockingBorderColor = UIManager.getColor("ToolBar.dockingForeground");
199         if ( floatingBorderColor == null ||
200              floatingBorderColor instanceof UIResource )
201             floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground");
202 
203         // ToolBar rollover button borders
204         Object rolloverProp = toolBar.getClientProperty( IS_ROLLOVER );
205         if (rolloverProp == null) {
206             rolloverProp = UIManager.get("ToolBar.isRollover");
207         }
208         if ( rolloverProp != null ) {
209             rolloverBorders = ((Boolean)rolloverProp).booleanValue();
210         }
211 
212         if (rolloverBorder == null) {
213             rolloverBorder = createRolloverBorder();
214         }
215         if (nonRolloverBorder == null) {
216             nonRolloverBorder = createNonRolloverBorder();
217         }
218         if (nonRolloverToggleBorder == null) {
219             nonRolloverToggleBorder = createNonRolloverToggleBorder();
220         }
221 
222 
223         setRolloverBorders( isRolloverBorders() );
224     }
225 
226     protected void uninstallDefaults( )
227     {
228         LookAndFeel.uninstallBorder(toolBar);
229         dockingColor = null;
230         floatingColor = null;
231         dockingBorderColor = null;
232         floatingBorderColor = null;
233 
234         installNormalBorders(toolBar);
235 
236         rolloverBorder = null;
237         nonRolloverBorder = null;
238         nonRolloverToggleBorder = null;
239     }
240 
241     protected void installComponents( )
242     {
243     }
244 
245     protected void uninstallComponents( )
246     {
247     }
248 
249     protected void installListeners( )
250     {
251         dockingListener = createDockingListener( );
252 
253         if ( dockingListener != null )
254         {
255             toolBar.addMouseMotionListener( dockingListener );
256             toolBar.addMouseListener( dockingListener );
257         }
258 
259         propertyListener = createPropertyListener();  // added in setFloating
260         if (propertyListener != null) {
261             toolBar.addPropertyChangeListener(propertyListener);
262         }
263 
264         toolBarContListener = createToolBarContListener();
265         if ( toolBarContListener != null ) {
266             toolBar.addContainerListener( toolBarContListener );
267         }
268 
269         toolBarFocusListener = createToolBarFocusListener();
270 
271         if ( toolBarFocusListener != null )
272         {
273             // Put focus listener on all components in toolbar
274             Component[] components = toolBar.getComponents();
275 
276             for (Component component : components) {
277                 component.addFocusListener(toolBarFocusListener);
278             }
279         }
280     }
281 
282     protected void uninstallListeners( )
283     {
284         if ( dockingListener != null )
285         {
286             toolBar.removeMouseMotionListener(dockingListener);
287             toolBar.removeMouseListener(dockingListener);
288 
289             dockingListener = null;
290         }
291 
292         if ( propertyListener != null )
293         {
294             toolBar.removePropertyChangeListener(propertyListener);
295             propertyListener = null;  // removed in setFloating
296         }
297 
298         if ( toolBarContListener != null )
299         {
300             toolBar.removeContainerListener( toolBarContListener );
301             toolBarContListener = null;
302         }
303 
304         if ( toolBarFocusListener != null )
305         {
306             // Remove focus listener from all components in toolbar
307             Component[] components = toolBar.getComponents();
308 
309             for (Component component : components) {
310                 component.removeFocusListener(toolBarFocusListener);
311             }
312 
313             toolBarFocusListener = null;
314         }
315         handler = null;
316     }
317 
318     protected void installKeyboardActions( )
319     {
320         InputMap km = getInputMap(JComponent.
321                                   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
322 
323         SwingUtilities.replaceUIInputMap(toolBar, JComponent.
324                                          WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
325                                          km);
326 
327     LazyActionMap.installLazyActionMap(toolBar, BasicToolBarUI.class,
328             "ToolBar.actionMap");
329     }
330 
331     InputMap getInputMap(int condition) {
332         if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
333             return (InputMap)DefaultLookup.get(toolBar, this,
334                     "ToolBar.ancestorInputMap");
335         }
336         return null;
337     }
338 
339     static void loadActionMap(LazyActionMap map) {
340         map.put(new Actions(Actions.NAVIGATE_RIGHT));
341         map.put(new Actions(Actions.NAVIGATE_LEFT));
342         map.put(new Actions(Actions.NAVIGATE_UP));
343         map.put(new Actions(Actions.NAVIGATE_DOWN));
344     }
345 
346     protected void uninstallKeyboardActions( )
347     {
348         SwingUtilities.replaceUIActionMap(toolBar, null);
349         SwingUtilities.replaceUIInputMap(toolBar, JComponent.
350                                          WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
351                                          null);
352     }
353 
354     protected void navigateFocusedComp( int direction )
355     {
356         int nComp = toolBar.getComponentCount();
357         int j;
358 
359         switch ( direction )
360         {
361             case EAST:
362             case SOUTH:
363 
364                 if ( focusedCompIndex < 0 || focusedCompIndex >= nComp ) break;
365 
366                 j = focusedCompIndex + 1;
367 
368                 while ( j != focusedCompIndex )
369                 {
370                     if ( j >= nComp ) j = 0;
371                     Component comp = toolBar.getComponentAtIndex( j++ );
372 
373                     if ( comp != null && comp.isFocusTraversable() && comp.isEnabled() )
374                     {
375                         comp.requestFocus();
376                         break;
377                     }
378                 }
379 
380                 break;
381 
382             case WEST:
383             case NORTH:
384 
385                 if ( focusedCompIndex < 0 || focusedCompIndex >= nComp ) break;
386 
387                 j = focusedCompIndex - 1;
388 
389                 while ( j != focusedCompIndex )
390                 {
391                     if ( j < 0 ) j = nComp - 1;
392                     Component comp = toolBar.getComponentAtIndex( j-- );
393 
394                     if ( comp != null && comp.isFocusTraversable() && comp.isEnabled() )
395                     {
396                         comp.requestFocus();
397                         break;
398                     }
399                 }
400 
401                 break;
402 
403             default:
404                 break;
405         }
406     }
407 
408     /**
409      * Creates a rollover border for toolbar components. The
410      * rollover border will be installed if rollover borders are
411      * enabled.
412      * <p>
413      * Override this method to provide an alternate rollover border.
414      *
415      * @since 1.4
416      */
417     protected Border createRolloverBorder() {
418         Object border = UIManager.get("ToolBar.rolloverBorder");
419         if (border != null) {
420             return (Border)border;
421         }
422         UIDefaults table = UIManager.getLookAndFeelDefaults();
423         return new CompoundBorder(new BasicBorders.RolloverButtonBorder(
424                                            table.getColor("controlShadow"),
425                                            table.getColor("controlDkShadow"),
426                                            table.getColor("controlHighlight"),
427                                            table.getColor("controlLtHighlight")),
428                                   new BasicBorders.RolloverMarginBorder());
429     }
430 
431     /**
432      * Creates the non rollover border for toolbar components. This
433      * border will be installed as the border for components added
434      * to the toolbar if rollover borders are not enabled.
435      * <p>
436      * Override this method to provide an alternate rollover border.
437      *
438      * @since 1.4
439      */
440     protected Border createNonRolloverBorder() {
441         Object border = UIManager.get("ToolBar.nonrolloverBorder");
442         if (border != null) {
443             return (Border)border;
444         }
445         UIDefaults table = UIManager.getLookAndFeelDefaults();
446         return new CompoundBorder(new BasicBorders.ButtonBorder(
447                                            table.getColor("Button.shadow"),
448                                            table.getColor("Button.darkShadow"),
449                                            table.getColor("Button.light"),
450                                            table.getColor("Button.highlight")),
451                                   new BasicBorders.RolloverMarginBorder());
452     }
453 
454     /**
455      * Creates a non rollover border for Toggle buttons in the toolbar.
456      */
457     private Border createNonRolloverToggleBorder() {
458         UIDefaults table = UIManager.getLookAndFeelDefaults();
459         return new CompoundBorder(new BasicBorders.RadioButtonBorder(
460                                            table.getColor("ToggleButton.shadow"),
461                                            table.getColor("ToggleButton.darkShadow"),
462                                            table.getColor("ToggleButton.light"),
463                                            table.getColor("ToggleButton.highlight")),
464                                   new BasicBorders.RolloverMarginBorder());
465     }
466 
467     /**
468      * No longer used, use BasicToolBarUI.createFloatingWindow(JToolBar)
469      * @see #createFloatingWindow
470      */
471     protected JFrame createFloatingFrame(JToolBar toolbar) {
472         Window window = SwingUtilities.getWindowAncestor(toolbar);
473         JFrame frame = new JFrame(toolbar.getName(),
474                                   (window != null) ? window.getGraphicsConfiguration() : null) {
475             // Override createRootPane() to automatically resize
476             // the frame when contents change
477             protected JRootPane createRootPane() {
478                 JRootPane rootPane = new JRootPane() {
479                     private boolean packing = false;
480 
481                     public void validate() {
482                         super.validate();
483                         if (!packing) {
484                             packing = true;
485                             pack();
486                             packing = false;
487                         }
488                     }
489                 };
490                 rootPane.setOpaque(true);
491                 return rootPane;
492             }
493         };
494         frame.getRootPane().setName("ToolBar.FloatingFrame");
495         frame.setResizable(false);
496         WindowListener wl = createFrameListener();
497         frame.addWindowListener(wl);
498         return frame;
499     }
500 
501     /**
502      * Creates a window which contains the toolbar after it has been
503      * dragged out from its container
504      * @return a <code>RootPaneContainer</code> object, containing the toolbar.
505      * @since 1.4
506      */
507     protected RootPaneContainer createFloatingWindow(JToolBar toolbar) {
508         class ToolBarDialog extends JDialog {
509             public ToolBarDialog(Frame owner, String title, boolean modal) {
510                 super(owner, title, modal);
511             }
512 
513             public ToolBarDialog(Dialog owner, String title, boolean modal) {
514                 super(owner, title, modal);
515             }
516 
517             // Override createRootPane() to automatically resize
518             // the frame when contents change
519             protected JRootPane createRootPane() {
520                 JRootPane rootPane = new JRootPane() {
521                     private boolean packing = false;
522 
523                     public void validate() {
524                         super.validate();
525                         if (!packing) {
526                             packing = true;
527                             pack();
528                             packing = false;
529                         }
530                     }
531                 };
532                 rootPane.setOpaque(true);
533                 return rootPane;
534             }
535         }
536 
537         JDialog dialog;
538         Window window = SwingUtilities.getWindowAncestor(toolbar);
539         if (window instanceof Frame) {
540             dialog = new ToolBarDialog((Frame)window, toolbar.getName(), false);
541         } else if (window instanceof Dialog) {
542             dialog = new ToolBarDialog((Dialog)window, toolbar.getName(), false);
543         } else {
544             dialog = new ToolBarDialog((Frame)null, toolbar.getName(), false);
545         }
546 
547         dialog.getRootPane().setName("ToolBar.FloatingWindow");
548         dialog.setTitle(toolbar.getName());
549         dialog.setResizable(false);
550         WindowListener wl = createFrameListener();
551         dialog.addWindowListener(wl);
552         return dialog;
553     }
554 
555     protected DragWindow createDragWindow(JToolBar toolbar) {
556         Window frame = null;
557         if(toolBar != null) {
558             Container p;
559             for(p = toolBar.getParent() ; p != null && !(p instanceof Window) ;
560                 p = p.getParent());
561             if(p != null && p instanceof Window)
562                 frame = (Window) p;
563         }
564         if(floatingToolBar == null) {
565             floatingToolBar = createFloatingWindow(toolBar);
566         }
567         if (floatingToolBar instanceof Window) frame = (Window) floatingToolBar;
568         DragWindow dragWindow = new DragWindow(frame);
569         return dragWindow;
570     }
571 
572     /**
573      * Returns a flag to determine whether rollover button borders
574      * are enabled.
575      *
576      * @return true if rollover borders are enabled; false otherwise
577      * @see #setRolloverBorders
578      * @since 1.4
579      */
580     public boolean isRolloverBorders() {
581         return rolloverBorders;
582     }
583 
584     /**
585      * Sets the flag for enabling rollover borders on the toolbar and it will
586      * also install the apropriate border depending on the state of the flag.
587      *
588      * @param rollover if true, rollover borders are installed.
589      *        Otherwise non-rollover borders are installed
590      * @see #isRolloverBorders
591      * @since 1.4
592      */
593     public void setRolloverBorders( boolean rollover ) {
594         rolloverBorders = rollover;
595 
596         if ( rolloverBorders )  {
597             installRolloverBorders( toolBar );
598         } else  {
599             installNonRolloverBorders( toolBar );
600         }
601     }
602 
603     /**
604      * Installs rollover borders on all the child components of the JComponent.
605      * <p>
606      * This is a convenience method to call <code>setBorderToRollover</code>
607      * for each child component.
608      *
609      * @param c container which holds the child components (usally a JToolBar)
610      * @see #setBorderToRollover
611      * @since 1.4
612      */
613     protected void installRolloverBorders ( JComponent c )  {
614         // Put rollover borders on buttons
615         Component[] components = c.getComponents();
616 
617         for (Component component : components) {
618             if (component instanceof JComponent) {
619                 ((JComponent) component).updateUI();
620                 setBorderToRollover(component);
621             }
622         }
623     }
624 
625     /**
626      * Installs non-rollover borders on all the child components of the JComponent.
627      * A non-rollover border is the border that is installed on the child component
628      * while it is in the toolbar.
629      * <p>
630      * This is a convenience method to call <code>setBorderToNonRollover</code>
631      * for each child component.
632      *
633      * @param c container which holds the child components (usally a JToolBar)
634      * @see #setBorderToNonRollover
635      * @since 1.4
636      */
637     protected void installNonRolloverBorders ( JComponent c )  {
638         // Put non-rollover borders on buttons. These borders reduce the margin.
639         Component[] components = c.getComponents();
640 
641         for (Component component : components) {
642             if (component instanceof JComponent) {
643                 ((JComponent) component).updateUI();
644                 setBorderToNonRollover(component);
645             }
646         }
647     }
648 
649     /**
650      * Installs normal borders on all the child components of the JComponent.
651      * A normal border is the original border that was installed on the child
652      * component before it was added to the toolbar.
653      * <p>
654      * This is a convenience method to call <code>setBorderNormal</code>
655      * for each child component.
656      *
657      * @param c container which holds the child components (usally a JToolBar)
658      * @see #setBorderToNonRollover
659      * @since 1.4
660      */
661     protected void installNormalBorders ( JComponent c )  {
662         // Put back the normal borders on buttons
663         Component[] components = c.getComponents();
664 
665         for (Component component : components) {
666             setBorderToNormal(component);
667         }
668     }
669 
670     /**
671      * Sets the border of the component to have a rollover border which
672      * was created by the {@link #createRolloverBorder} method.
673      *
674      * @param c component which will have a rollover border installed
675      * @see #createRolloverBorder
676      * @since 1.4
677      */
678     protected void setBorderToRollover(Component c) {
679         if (c instanceof AbstractButton) {
680             AbstractButton b = (AbstractButton)c;
681 
682             Border border = borderTable.get(b);
683             if (border == null || border instanceof UIResource) {
684                 borderTable.put(b, b.getBorder());
685             }
686 
687             // Only set the border if its the default border
688             if (b.getBorder() instanceof UIResource) {
689                 b.setBorder(getRolloverBorder(b));
690             }
691 
692             rolloverTable.put(b, b.isRolloverEnabled()?
693                               Boolean.TRUE: Boolean.FALSE);
694             b.setRolloverEnabled(true);
695         }
696     }
697 
698     /**
699      * Returns a rollover border for the button.
700      *
701      * @param b the button to calculate the rollover border for
702      * @return the rollover border
703      * @see #setBorderToRollover
704      * @since 1.6
705      */
706     protected Border getRolloverBorder(AbstractButton b) {
707         return rolloverBorder;
708     }
709 
710     /**
711      * Sets the border of the component to have a non-rollover border which
712      * was created by the {@link #createNonRolloverBorder} method.
713      *
714      * @param c component which will have a non-rollover border installed
715      * @see #createNonRolloverBorder
716      * @since 1.4
717      */
718     protected void setBorderToNonRollover(Component c) {
719         if (c instanceof AbstractButton) {
720             AbstractButton b = (AbstractButton)c;
721 
722             Border border = borderTable.get(b);
723             if (border == null || border instanceof UIResource) {
724                 borderTable.put(b, b.getBorder());
725             }
726 
727             // Only set the border if its the default border
728             if (b.getBorder() instanceof UIResource) {
729                 b.setBorder(getNonRolloverBorder(b));
730             }
731             rolloverTable.put(b, b.isRolloverEnabled()?
732                               Boolean.TRUE: Boolean.FALSE);
733             b.setRolloverEnabled(false);
734         }
735     }
736 
737     /**
738      * Returns a non-rollover border for the button.
739      *
740      * @param b the button to calculate the non-rollover border for
741      * @return the non-rollover border
742      * @see #setBorderToNonRollover
743      * @since 1.6
744      */
745     protected Border getNonRolloverBorder(AbstractButton b) {
746         if (b instanceof JToggleButton) {
747             return nonRolloverToggleBorder;
748         } else {
749             return nonRolloverBorder;
750         }
751     }
752 
753     /**
754      * Sets the border of the component to have a normal border.
755      * A normal border is the original border that was installed on the child
756      * component before it was added to the toolbar.
757      *
758      * @param c component which will have a normal border re-installed
759      * @see #createNonRolloverBorder
760      * @since 1.4
761      */
762     protected void setBorderToNormal(Component c) {
763         if (c instanceof AbstractButton) {
764             AbstractButton b = (AbstractButton)c;
765 
766             Border border = borderTable.remove(b);
767             b.setBorder(border);
768 
769             Boolean value = rolloverTable.remove(b);
770             if (value != null) {
771                 b.setRolloverEnabled(value.booleanValue());
772             }
773         }
774     }
775 
776     public void setFloatingLocation(int x, int y) {
777         floatingX = x;
778         floatingY = y;
779     }
780 
781     public boolean isFloating() {
782         return floating;
783     }
784 
785     public void setFloating(boolean b, Point p) {
786         if (toolBar.isFloatable()) {
787             boolean visible = false;
788             Window ancestor = SwingUtilities.getWindowAncestor(toolBar);
789             if (ancestor != null) {
790                 visible = ancestor.isVisible();
791             }
792             if (dragWindow != null)
793                 dragWindow.setVisible(false);
794             this.floating = b;
795             if (floatingToolBar == null) {
796                 floatingToolBar = createFloatingWindow(toolBar);
797             }
798             if (b == true)
799             {
800                 if (dockingSource == null)
801                 {
802                     dockingSource = toolBar.getParent();
803                     dockingSource.remove(toolBar);
804                 }
805                 constraintBeforeFloating = calculateConstraint();
806                 if ( propertyListener != null )
807                     UIManager.addPropertyChangeListener( propertyListener );
808                 floatingToolBar.getContentPane().add(toolBar,BorderLayout.CENTER);
809                 if (floatingToolBar instanceof Window) {
810                     ((Window)floatingToolBar).pack();
811                     ((Window)floatingToolBar).setLocation(floatingX, floatingY);
812                     if (visible) {
813                         ((Window)floatingToolBar).show();
814                     } else {
815                         ancestor.addWindowListener(new WindowAdapter() {
816                             public void windowOpened(WindowEvent e) {
817                                 ((Window)floatingToolBar).show();
818                             }
819                         });
820                     }
821                 }
822             } else {
823                 if (floatingToolBar == null)
824                     floatingToolBar = createFloatingWindow(toolBar);
825                 if (floatingToolBar instanceof Window) ((Window)floatingToolBar).setVisible(false);
826                 floatingToolBar.getContentPane().remove(toolBar);
827                 String constraint = getDockingConstraint(dockingSource,
828                                                          p);
829                 if (constraint == null) {
830                     constraint = BorderLayout.NORTH;
831                 }
832                 int orientation = mapConstraintToOrientation(constraint);
833                 setOrientation(orientation);
834                 if (dockingSource== null)
835                     dockingSource = toolBar.getParent();
836                 if ( propertyListener != null )
837                     UIManager.removePropertyChangeListener( propertyListener );
838                 dockingSource.add(constraint, toolBar);
839             }
840             dockingSource.invalidate();
841             Container dockingSourceParent = dockingSource.getParent();
842             if (dockingSourceParent != null)
843                 dockingSourceParent.validate();
844             dockingSource.repaint();
845         }
846     }
847 
848     private int mapConstraintToOrientation(String constraint)
849     {
850         int orientation = toolBar.getOrientation();
851 
852         if ( constraint != null )
853         {
854             if ( constraint.equals(BorderLayout.EAST) || constraint.equals(BorderLayout.WEST) )
855                 orientation = JToolBar.VERTICAL;
856             else if ( constraint.equals(BorderLayout.NORTH) || constraint.equals(BorderLayout.SOUTH) )
857                 orientation = JToolBar.HORIZONTAL;
858         }
859 
860         return orientation;
861     }
862 
863     public void setOrientation(int orientation)
864     {
865         toolBar.setOrientation( orientation );
866 
867         if (dragWindow !=null)
868             dragWindow.setOrientation(orientation);
869     }
870 
871     /**
872      * Gets the color displayed when over a docking area
873      */
874     public Color getDockingColor() {
875         return dockingColor;
876     }
877 
878     /**
879      * Sets the color displayed when over a docking area
880      */
881    public void setDockingColor(Color c) {
882         this.dockingColor = c;
883     }
884 
885     /**
886      * Gets the color displayed when over a floating area
887      */
888     public Color getFloatingColor() {
889         return floatingColor;
890     }
891 
892     /**
893      * Sets the color displayed when over a floating area
894      */
895     public void setFloatingColor(Color c) {
896         this.floatingColor = c;
897     }
898 
899     private boolean isBlocked(Component comp, Object constraint) {
900         if (comp instanceof Container) {
901             Container cont = (Container)comp;
902             LayoutManager lm = cont.getLayout();
903             if (lm instanceof BorderLayout) {
904                 BorderLayout blm = (BorderLayout)lm;
905                 Component c = blm.getLayoutComponent(cont, constraint);
906                 return (c != null && c != toolBar);
907             }
908         }
909         return false;
910     }
911 
912     public boolean canDock(Component c, Point p) {
913         return (p != null && getDockingConstraint(c, p) != null);
914     }
915 
916     private String calculateConstraint() {
917         String constraint = null;
918         LayoutManager lm = dockingSource.getLayout();
919         if (lm instanceof BorderLayout) {
920             constraint = (String)((BorderLayout)lm).getConstraints(toolBar);
921         }
922         return (constraint != null) ? constraint : constraintBeforeFloating;
923     }
924 
925 
926 
927     private String getDockingConstraint(Component c, Point p) {
928         if (p == null) return constraintBeforeFloating;
929         if (c.contains(p)) {
930             dockingSensitivity = (toolBar.getOrientation() == JToolBar.HORIZONTAL)
931                                                 ? toolBar.getSize().height
932                                                 : toolBar.getSize().width;
933             // North  (Base distance on height for now!)
934             if (p.y < dockingSensitivity && !isBlocked(c, BorderLayout.NORTH)) {
935                 return BorderLayout.NORTH;
936             }
937             // East  (Base distance on height for now!)
938             if (p.x >= c.getWidth() - dockingSensitivity && !isBlocked(c, BorderLayout.EAST)) {
939                 return BorderLayout.EAST;
940             }
941             // West  (Base distance on height for now!)
942             if (p.x < dockingSensitivity && !isBlocked(c, BorderLayout.WEST)) {
943                 return BorderLayout.WEST;
944             }
945             if (p.y >= c.getHeight() - dockingSensitivity && !isBlocked(c, BorderLayout.SOUTH)) {
946                 return BorderLayout.SOUTH;
947             }
948         }
949         return null;
950     }
951 
952     protected void dragTo(Point position, Point origin)
953     {
954         if (toolBar.isFloatable())
955         {
956           try
957           {
958             if (dragWindow == null)
959                 dragWindow = createDragWindow(toolBar);
960             Point offset = dragWindow.getOffset();
961             if (offset == null) {
962                 Dimension size = toolBar.getPreferredSize();
963                 offset = new Point(size.width/2, size.height/2);
964                 dragWindow.setOffset(offset);
965             }
966             Point global = new Point(origin.x+ position.x,
967                                      origin.y+position.y);
968             Point dragPoint = new Point(global.x- offset.x,
969                                         global.y- offset.y);
970             if (dockingSource == null)
971                 dockingSource = toolBar.getParent();
972                 constraintBeforeFloating = calculateConstraint();
973             Point dockingPosition = dockingSource.getLocationOnScreen();
974             Point comparisonPoint = new Point(global.x-dockingPosition.x,
975                                               global.y-dockingPosition.y);
976             if (canDock(dockingSource, comparisonPoint)) {
977                 dragWindow.setBackground(getDockingColor());
978                 String constraint = getDockingConstraint(dockingSource,
979                                                          comparisonPoint);
980                 int orientation = mapConstraintToOrientation(constraint);
981                 dragWindow.setOrientation(orientation);
982                 dragWindow.setBorderColor(dockingBorderColor);
983             } else {
984                 dragWindow.setBackground(getFloatingColor());
985                 dragWindow.setBorderColor(floatingBorderColor);
986                 dragWindow.setOrientation(toolBar.getOrientation());
987             }
988 
989             dragWindow.setLocation(dragPoint.x, dragPoint.y);
990             if (dragWindow.isVisible() == false) {
991                 Dimension size = toolBar.getPreferredSize();
992                 dragWindow.setSize(size.width, size.height);
993                 dragWindow.show();
994             }
995           }
996           catch ( IllegalComponentStateException e )
997           {
998           }
999         }
1000     }
1001 
1002     protected void floatAt(Point position, Point origin)
1003     {
1004         if(toolBar.isFloatable())
1005         {
1006           try
1007           {
1008             Point offset = dragWindow.getOffset();
1009             if (offset == null) {
1010                 offset = position;
1011                 dragWindow.setOffset(offset);
1012             }
1013             Point global = new Point(origin.x+ position.x,
1014                                      origin.y+position.y);
1015             setFloatingLocation(global.x-offset.x,
1016                                 global.y-offset.y);
1017             if (dockingSource != null) {
1018                 Point dockingPosition = dockingSource.getLocationOnScreen();
1019                 Point comparisonPoint = new Point(global.x-dockingPosition.x,
1020                                                   global.y-dockingPosition.y);
1021                 if (canDock(dockingSource, comparisonPoint)) {
1022                     setFloating(false, comparisonPoint);
1023                 } else {
1024                     setFloating(true, null);
1025                 }
1026             } else {
1027                 setFloating(true, null);
1028             }
1029             dragWindow.setOffset(null);
1030           }
1031           catch ( IllegalComponentStateException e )
1032           {
1033           }
1034         }
1035     }
1036 
1037     private Handler getHandler() {
1038         if (handler == null) {
1039             handler = new Handler();
1040         }
1041         return handler;
1042     }
1043 
1044     protected ContainerListener createToolBarContListener( )
1045     {
1046         return getHandler();
1047     }
1048 
1049     protected FocusListener createToolBarFocusListener( )
1050     {
1051         return getHandler();
1052     }
1053 
1054     protected PropertyChangeListener createPropertyListener()
1055     {
1056         return getHandler();
1057     }
1058 
1059     protected MouseInputListener createDockingListener( ) {
1060         getHandler().tb = toolBar;
1061         return getHandler();
1062     }
1063 
1064     protected WindowListener createFrameListener() {
1065         return new FrameListener();
1066     }
1067 
1068     /**
1069      * Paints the contents of the window used for dragging.
1070      *
1071      * @param g Graphics to paint to.
1072      * @throws NullPointerException is <code>g</code> is null
1073      * @since 1.5
1074      */
1075     protected void paintDragWindow(Graphics g) {
1076         g.setColor(dragWindow.getBackground());
1077         int w = dragWindow.getWidth();
1078         int h = dragWindow.getHeight();
1079         g.fillRect(0, 0, w, h);
1080         g.setColor(dragWindow.getBorderColor());
1081         g.drawRect(0, 0, w - 1, h - 1);
1082     }
1083 
1084 
1085     private static class Actions extends UIAction {
1086         private static final String NAVIGATE_RIGHT = "navigateRight";
1087         private static final String NAVIGATE_LEFT = "navigateLeft";
1088         private static final String NAVIGATE_UP = "navigateUp";
1089         private static final String NAVIGATE_DOWN = "navigateDown";
1090 
1091         public Actions(String name) {
1092             super(name);
1093         }
1094 
1095         public void actionPerformed(ActionEvent evt) {
1096             String key = getName();
1097             JToolBar toolBar = (JToolBar)evt.getSource();
1098             BasicToolBarUI ui = (BasicToolBarUI)BasicLookAndFeel.getUIOfType(
1099                      toolBar.getUI(), BasicToolBarUI.class);
1100 
1101             if (NAVIGATE_RIGHT == key) {
1102                 ui.navigateFocusedComp(EAST);
1103             } else if (NAVIGATE_LEFT == key) {
1104                 ui.navigateFocusedComp(WEST);
1105             } else if (NAVIGATE_UP == key) {
1106                 ui.navigateFocusedComp(NORTH);
1107             } else if (NAVIGATE_DOWN == key) {
1108                 ui.navigateFocusedComp(SOUTH);
1109             }
1110         }
1111     }
1112 
1113 
1114     private class Handler implements ContainerListener,
1115             FocusListener, MouseInputListener, PropertyChangeListener {
1116 
1117         //
1118         // ContainerListener
1119         //
1120         public void componentAdded(ContainerEvent evt) {
1121             Component c = evt.getChild();
1122 
1123             if (toolBarFocusListener != null) {
1124                 c.addFocusListener(toolBarFocusListener);
1125             }
1126 
1127             if (isRolloverBorders()) {
1128                 setBorderToRollover(c);
1129             } else {
1130                 setBorderToNonRollover(c);
1131             }
1132         }
1133 
1134         public void componentRemoved(ContainerEvent evt) {
1135             Component c = evt.getChild();
1136 
1137             if (toolBarFocusListener != null) {
1138                 c.removeFocusListener(toolBarFocusListener);
1139             }
1140 
1141             // Revert the button border
1142             setBorderToNormal(c);
1143         }
1144 
1145 
1146         //
1147         // FocusListener
1148         //
1149         public void focusGained(FocusEvent evt) {
1150             Component c = evt.getComponent();
1151             focusedCompIndex = toolBar.getComponentIndex(c);
1152         }
1153 
1154         public void focusLost(FocusEvent evt) { }
1155 
1156 
1157         //
1158         // MouseInputListener (DockingListener)
1159         //
1160         JToolBar tb;
1161         boolean isDragging = false;
1162         Point origin = null;
1163 
1164         public void mousePressed(MouseEvent evt) {
1165             if (!tb.isEnabled()) {
1166                 return;
1167             }
1168             isDragging = false;
1169         }
1170 
1171         public void mouseReleased(MouseEvent evt) {
1172             if (!tb.isEnabled()) {
1173                 return;
1174             }
1175             if (isDragging) {
1176                 Point position = evt.getPoint();
1177                 if (origin == null)
1178                     origin = evt.getComponent().getLocationOnScreen();
1179                 floatAt(position, origin);
1180             }
1181             origin = null;
1182             isDragging = false;
1183         }
1184 
1185         public void mouseDragged(MouseEvent evt) {
1186             if (!tb.isEnabled()) {
1187                 return;
1188             }
1189             isDragging = true;
1190             Point position = evt.getPoint();
1191             if (origin == null) {
1192                 origin = evt.getComponent().getLocationOnScreen();
1193             }
1194             dragTo(position, origin);
1195         }
1196 
1197         public void mouseClicked(MouseEvent evt) {}
1198         public void mouseEntered(MouseEvent evt) {}
1199         public void mouseExited(MouseEvent evt) {}
1200         public void mouseMoved(MouseEvent evt) {}
1201 
1202 
1203         //
1204         // PropertyChangeListener
1205         //
1206         public void propertyChange(PropertyChangeEvent evt) {
1207             String propertyName = evt.getPropertyName();
1208             if (propertyName == "lookAndFeel") {
1209                 toolBar.updateUI();
1210             } else if (propertyName == "orientation") {
1211                 // Search for JSeparator components and change it's orientation
1212                 // to match the toolbar and flip it's orientation.
1213                 Component[] components = toolBar.getComponents();
1214                 int orientation = ((Integer)evt.getNewValue()).intValue();
1215                 JToolBar.Separator separator;
1216 
1217                 for (int i = 0; i < components.length; ++i) {
1218                     if (components[i] instanceof JToolBar.Separator) {
1219                         separator = (JToolBar.Separator)components[i];
1220                         if ((orientation == JToolBar.HORIZONTAL)) {
1221                             separator.setOrientation(JSeparator.VERTICAL);
1222                         } else {
1223                             separator.setOrientation(JSeparator.HORIZONTAL);
1224                         }
1225                         Dimension size = separator.getSeparatorSize();
1226                         if (size != null && size.width != size.height) {
1227                             // Flip the orientation.
1228                             Dimension newSize =
1229                                 new Dimension(size.height, size.width);
1230                             separator.setSeparatorSize(newSize);
1231                         }
1232                     }
1233                 }
1234             } else if (propertyName == IS_ROLLOVER) {
1235                 installNormalBorders(toolBar);
1236                 setRolloverBorders(((Boolean)evt.getNewValue()).booleanValue());
1237             }
1238         }
1239     }
1240 
1241     protected class FrameListener extends WindowAdapter {
1242         public void windowClosing(WindowEvent w) {
1243             if (toolBar.isFloatable()) {
1244                 if (dragWindow != null)
1245                     dragWindow.setVisible(false);
1246                 floating = false;
1247                 if (floatingToolBar == null)
1248                     floatingToolBar = createFloatingWindow(toolBar);
1249                 if (floatingToolBar instanceof Window) ((Window)floatingToolBar).setVisible(false);
1250                 floatingToolBar.getContentPane().remove(toolBar);
1251                 String constraint = constraintBeforeFloating;
1252                 if (toolBar.getOrientation() == JToolBar.HORIZONTAL) {
1253                     if (constraint == "West" || constraint == "East") {
1254                         constraint = "North";
1255                     }
1256                 } else {
1257                     if (constraint == "North" || constraint == "South") {
1258                         constraint = "West";
1259                     }
1260                 }
1261                 if (dockingSource == null)
1262                     dockingSource = toolBar.getParent();
1263                 if (propertyListener != null)
1264                     UIManager.removePropertyChangeListener(propertyListener);
1265                 dockingSource.add(toolBar, constraint);
1266                 dockingSource.invalidate();
1267                 Container dockingSourceParent = dockingSource.getParent();
1268                 if (dockingSourceParent != null)
1269                         dockingSourceParent.validate();
1270                 dockingSource.repaint();
1271             }
1272         }
1273 
1274     }
1275 
1276     protected class ToolBarContListener implements ContainerListener {
1277         // NOTE: This class exists only for backward compatability. All
1278         // its functionality has been moved into Handler. If you need to add
1279         // new functionality add it to the Handler, but make sure this
1280         // class calls into the Handler.
1281         public void componentAdded( ContainerEvent e )  {
1282             getHandler().componentAdded(e);
1283         }
1284 
1285         public void componentRemoved( ContainerEvent e ) {
1286             getHandler().componentRemoved(e);
1287         }
1288 
1289     }
1290 
1291     protected class ToolBarFocusListener implements FocusListener {
1292         // NOTE: This class exists only for backward compatability. All
1293         // its functionality has been moved into Handler. If you need to add
1294         // new functionality add it to the Handler, but make sure this
1295         // class calls into the Handler.
1296         public void focusGained( FocusEvent e ) {
1297             getHandler().focusGained(e);
1298             }
1299 
1300         public void focusLost( FocusEvent e ) {
1301             getHandler().focusLost(e);
1302             }
1303     }
1304 
1305     protected class PropertyListener implements PropertyChangeListener {
1306         // NOTE: This class exists only for backward compatability. All
1307         // its functionality has been moved into Handler. If you need to add
1308         // new functionality add it to the Handler, but make sure this
1309         // class calls into the Handler.
1310         public void propertyChange( PropertyChangeEvent e ) {
1311             getHandler().propertyChange(e);
1312             }
1313     }
1314 
1315     /**
1316      * This class should be treated as a &quot;protected&quot; inner class.
1317      * Instantiate it only within subclasses of BasicToolBarUI.
1318      */
1319     public class DockingListener implements MouseInputListener {
1320         // NOTE: This class exists only for backward compatability. All
1321         // its functionality has been moved into Handler. If you need to add
1322         // new functionality add it to the Handler, but make sure this
1323         // class calls into the Handler.
1324         protected JToolBar toolBar;
1325         protected boolean isDragging = false;
1326         protected Point origin = null;
1327 
1328         public DockingListener(JToolBar t) {
1329             this.toolBar = t;
1330             getHandler().tb = t;
1331         }
1332 
1333         public void mouseClicked(MouseEvent e) {
1334         getHandler().mouseClicked(e);
1335     }
1336 
1337         public void mousePressed(MouseEvent e) {
1338         getHandler().tb = toolBar;
1339         getHandler().mousePressed(e);
1340         isDragging = getHandler().isDragging;
1341         }
1342 
1343         public void mouseReleased(MouseEvent e) {
1344         getHandler().tb = toolBar;
1345         getHandler().isDragging = isDragging;
1346         getHandler().origin = origin;
1347         getHandler().mouseReleased(e);
1348         isDragging = getHandler().isDragging;
1349         origin = getHandler().origin;
1350         }
1351 
1352         public void mouseEntered(MouseEvent e) {
1353         getHandler().mouseEntered(e);
1354     }
1355 
1356         public void mouseExited(MouseEvent e) {
1357         getHandler().mouseExited(e);
1358     }
1359 
1360         public void mouseDragged(MouseEvent e) {
1361         getHandler().tb = toolBar;
1362         getHandler().origin = origin;
1363         getHandler().mouseDragged(e);
1364         isDragging = getHandler().isDragging;
1365         origin = getHandler().origin;
1366         }
1367 
1368         public void mouseMoved(MouseEvent e) {
1369         getHandler().mouseMoved(e);
1370         }
1371     }
1372 
1373     protected class DragWindow extends Window
1374     {
1375         Color borderColor = Color.gray;
1376         int orientation = toolBar.getOrientation();
1377         Point offset; // offset of the mouse cursor inside the DragWindow
1378 
1379         DragWindow(Window w) {
1380             super(w);
1381         }
1382 
1383     /**
1384      * Returns the orientation of the toolbar window when the toolbar is
1385      * floating. The orientation is either one of <code>JToolBar.HORIZONTAL</code>
1386      * or <code>JToolBar.VERTICAL</code>.
1387      *
1388      * @return the orientation of the toolbar window
1389      * @since 1.6
1390      */
1391     public int getOrientation() {
1392         return orientation;
1393     }
1394 
1395         public void setOrientation(int o) {
1396             if(isShowing()) {
1397                 if (o == this.orientation)
1398                     return;
1399                 this.orientation = o;
1400                 Dimension size = getSize();
1401                 setSize(new Dimension(size.height, size.width));
1402                 if (offset!=null) {
1403                     if( BasicGraphicsUtils.isLeftToRight(toolBar) ) {
1404                         setOffset(new Point(offset.y, offset.x));
1405                     } else if( o == JToolBar.HORIZONTAL ) {
1406                         setOffset(new Point( size.height-offset.y, offset.x));
1407                     } else {
1408                         setOffset(new Point(offset.y, size.width-offset.x));
1409                     }
1410                 }
1411                 repaint();
1412             }
1413         }
1414 
1415         public Point getOffset() {
1416             return offset;
1417         }
1418 
1419         public void setOffset(Point p) {
1420             this.offset = p;
1421         }
1422 
1423         public void setBorderColor(Color c) {
1424             if (this.borderColor == c)
1425                 return;
1426             this.borderColor = c;
1427             repaint();
1428         }
1429 
1430         public Color getBorderColor() {
1431             return this.borderColor;
1432         }
1433 
1434         public void paint(Graphics g) {
1435             paintDragWindow(g);
1436             // Paint the children
1437             super.paint(g);
1438         }
1439         public Insets getInsets() {
1440             return new Insets(1,1,1,1);
1441         }
1442     }
1443 }